package com.whfc.fvs.service.impl;

import com.whfc.common.enums.DelFlag;
import com.whfc.common.exception.BizException;
import com.whfc.common.result.ListData;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.vs.ezviz.EzvizApi;
import com.whfc.common.vs.ezviz.entity.EzvizChannelInfo;
import com.whfc.common.vs.ezviz.entity.EzvizRecordInfo;
import com.whfc.common.vs.ezviz.entity.EzvizStreamInfo;
import com.whfc.common.vs.ezviz.enums.EzvizDevicePtzStatus;
import com.whfc.common.vs.ezviz.enums.EzvizDeviceStatus;
import com.whfc.fvs.dao.FvsDeviceMapper;
import com.whfc.fvs.dao.FvsStreamMapper;
import com.whfc.fvs.dto.*;
import com.whfc.fvs.entity.FvsDevice;
import com.whfc.fvs.entity.FvsStream;
import com.whfc.fvs.enums.*;
import com.whfc.fvs.param.FvsDeviceAddParam;
import com.whfc.fvs.service.FvsPlatformService;
import com.whfc.fvs.service.factroy.FvsPlatformConstant;
import com.whfc.fvs.service.manager.FvsTokenMgr;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 萤石云 Service
 *
 * @author qzexing
 * @version 1.0
 * @date 2020/4/29 21:49
 */
@Service(FvsPlatformConstant.EZVIZ_SERVICE)
public class FvsEzvizVsServiceImpl implements FvsPlatformService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 一天
     */
    private static final long ONE_DAY_MILLS = 24 * 60 * 60 * 1000;

    @Autowired
    private FvsDeviceMapper fvsDeviceMapper;

    @Autowired
    private FvsStreamMapper fvsStreamMapper;

    @Autowired
    private FvsTokenMgr fvsTokenMgr;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addDevice(FvsDeviceDTO fvsDeviceDTO, FvsDeviceAddParam deviceAddParam) {
        String deviceSerial = deviceAddParam.getUsername();
        if (StringUtils.isEmpty(deviceSerial)) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "设备序列号不能为空.");
        }
        String validateCode = deviceAddParam.getPassword();
        if (StringUtils.isEmpty(validateCode)) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "设备验证码不能为空.");
        }
        Integer deviceType = deviceAddParam.getDeviceType();
        if (deviceType == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "设备类型不能为空.");
        }
        FvsDeviceType type = FvsDeviceType.parseValue(deviceType);
        if (type == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "设备类型错误.");
        }

        //获取萤石云登录token
        String accessToken = fvsTokenMgr.getEzvizAccessToken(fvsDeviceDTO.getDeptId());
        //调用API添加设备,如果错误会报异常
        EzvizApi.createDevice(accessToken, deviceSerial, validateCode);
        //更新设备信息
        FvsDevice fvsDevice = new FvsDevice();
        fvsDevice.setId(fvsDeviceDTO.getId());
        fvsDevice.setUsername(deviceSerial);
        fvsDevice.setPassword(validateCode);
        fvsDevice.setDeviceType(deviceType);
        fvsDevice.setPtz(isSupportPtz(accessToken, deviceSerial).getValue());
        fvsDeviceMapper.updateByPrimaryKeySelective(fvsDevice);

        //获取通道信息
        getChannelList(accessToken, fvsDeviceDTO.getId());
        //设备解密
        EzvizApi.deviceDecrypt(accessToken, deviceSerial, validateCode);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteDevice(FvsDeviceDTO fvsDeviceDTO) {
        //获取登录token和设备序列号
        String accessToken = fvsTokenMgr.getEzvizAccessToken(fvsDeviceDTO.getDeptId());
        String deviceSerial = fvsDeviceDTO.getUsername();
        if (FvsDeviceType.DVR.getValue().equals(fvsDeviceDTO.getDeviceType())) {
            //从萤石云平台删除设备
            EzvizApi.delDevice(accessToken, deviceSerial);
            //如果当前设备是硬盘录像机
            //逻辑删除硬盘录像机下面的所有摄像头
            fvsDeviceMapper.logicDeleteByPid(fvsDeviceDTO.getId());
        } else if (0 == fvsDeviceDTO.getPid()) {
            //从萤石云平台删除设备
            EzvizApi.delDevice(accessToken, deviceSerial);
        }
    }


    @Override
    public String getSnapshotUrl(FvsDeviceDTO fvsDeviceDTO) {
        //获取登录token和设备序列号
        String accessToken = fvsTokenMgr.getEzvizAccessToken(fvsDeviceDTO.getDeptId());
        String deviceSerial = fvsDeviceDTO.getUsername();

        //获取萤石云抓取图片地址
        return EzvizApi.getSnapshotUrl(accessToken, deviceSerial, fvsDeviceDTO.getChannelNo());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FvsStreamDTO getStreamUrl(FvsDeviceDTO fvsDeviceDTO) {
        // 播放地址过期，需要重新获取
        String accessToken = fvsTokenMgr.getEzvizAccessToken(fvsDeviceDTO.getDeptId());
        String deviceSerial = fvsDeviceDTO.getUsername();
        Integer channelNo = fvsDeviceDTO.getChannelNo();
        FvsStream fvsStream = fvsStreamMapper.selectStreamByDeviceId(fvsDeviceDTO.getId());
        boolean isNeedRefresh = false;
        //没有视频播放地址
        if (fvsStream == null) {
            isNeedRefresh = true;
            fvsStream = new FvsStream();
        }
        //视频播放地址过期
        else {
            long timeDiff = fvsStream.getExpireTime().getTime() - System.currentTimeMillis();
            if (timeDiff < ONE_DAY_MILLS) {
                isNeedRefresh = true;
            }
        }
        if (isNeedRefresh) {
            EzvizStreamInfo streamUrl = EzvizApi.getStreamUrl(accessToken, deviceSerial, channelNo);
            fvsStream.setDeviceId(fvsDeviceDTO.getId());
            fvsStream.setEzopen(streamUrl.getEzopen());
            fvsStream.setEzopenHd(streamUrl.getEzopenHd());
            fvsStream.setHls(streamUrl.getHls());
            fvsStream.setHlsHd(streamUrl.getHlsHd());
            fvsStream.setRtmp(streamUrl.getRtmp());
            fvsStream.setRtmpHd(streamUrl.getRtmpHd());
            fvsStream.setExpireTime(streamUrl.getExpireTime());
            fvsStream.setDelFlag(DelFlag.UNDELETE.getValue());
            fvsStreamMapper.insertOrUpdate(fvsStream);
        }
        FvsStreamDTO streamDTO = new FvsStreamDTO();
        BeanUtils.copyProperties(fvsStream, streamDTO);
        return streamDTO;
    }


    @Override
    public ListData<FvsRecordDTO> getRecordList(FvsDeviceDTO fvsDeviceDTO, Date startTime, Date endTime) {
        //获取登录token和设备序列号
        String accessToken = fvsTokenMgr.getEzvizAccessToken(fvsDeviceDTO.getDeptId());
        String deviceSerial = fvsDeviceDTO.getUsername();

        ListData<FvsRecordDTO> listData = new ListData<>();
        List<FvsRecordDTO> list = new ArrayList<>();
        List<EzvizRecordInfo> recordList = EzvizApi.getRecordList(accessToken, deviceSerial, fvsDeviceDTO.getChannelNo(), startTime, endTime);
        if (recordList == null || recordList.isEmpty()) {
            listData.setList(list);
            return listData;
        }
        for (EzvizRecordInfo record : recordList) {
            FvsRecordDTO appFvsRecordDTO = new FvsRecordDTO();
            Date start = new Date(record.getStartTime());
            Date end = new Date(record.getEndTime());
            appFvsRecordDTO.setStartTime(start);
            appFvsRecordDTO.setEndTime(end);
            String recordUrl = record.getRecordURL();
            appFvsRecordDTO.setRecordUrl(recordUrl);
            list.add(appFvsRecordDTO);
        }
        listData.setList(list);
        return listData;
    }


    /**
     * 萤石云开启云台
     */
    @Override
    public void ptz(FvsDeviceDTO fvsDeviceDTO, FvsDevicePtzOption devicePtzOption) {
        //获取登录token和设备序列号
        String accessToken = fvsTokenMgr.getEzvizAccessToken(fvsDeviceDTO.getDeptId());
        String deviceSerial = fvsDeviceDTO.getUsername();

        Boolean bool = EzvizApi.startPtz(accessToken, deviceSerial, fvsDeviceDTO.getChannelNo(), devicePtzOption.getValue());
        if (!bool) {
            logger.info(fvsDeviceDTO.getUsername() + " 设备不支持云台操作.");
            Integer deviceId = fvsDeviceDTO.getId();
            FvsDevice fvsDevice = fvsDeviceMapper.selectByPrimaryKey(deviceId);
            if (fvsDevice != null) {
                fvsDevice.setPtz(FvsDevicePtzStatus.NOT_SUPPORT_PTZ.getValue());
                fvsDeviceMapper.updateByPrimaryKeySelective(fvsDevice);
            }
            throw new BizException(ResultEnum.FAILURE.getCode(), "该设备不支持云台操作.");
        }
    }

    @Override
    public FvsTokenDTO getToken(Integer deptId) {
        FvsTokenDTO fvsTokenDTO = new FvsTokenDTO();
        fvsTokenDTO.setToken(fvsTokenMgr.getEzvizAccessToken(deptId));
        FvsSettingDTO fvsSettingDTO = fvsTokenMgr.getFvsSetting(deptId, VsPlatform.HIK_EZVIZ);
        String appKey = fvsSettingDTO != null ? fvsSettingDTO.getAppKey() : "";
        fvsTokenDTO.setAppKey(appKey);
        return fvsTokenDTO;
    }

    /**
     * 获取设备状态
     *
     * @param deviceSerial 设备序列号
     * @return 设备状态
     */
    public FvsDeviceStatus getDeviceStatus(Integer deptId, String deviceSerial) {
        //默认设备状态
        FvsDeviceStatus status = FvsDeviceStatus.OFFLINE;
        String accessToken = fvsTokenMgr.getEzvizAccessToken(deptId);
        //获取设备状态
        EzvizDeviceStatus deviceStatus = EzvizApi.getDeviceStatus(accessToken, deviceSerial);
        if (deviceStatus != null) {
            //解析状态
            status = FvsDeviceStatus.parseValue(deviceStatus.getValue());
        }
        return status;
    }

    /**
     * 获取通道列表
     *
     * @param accessToken accessToken
     * @param deviceId    设备ID
     */
    private void getChannelList(String accessToken, Integer deviceId) {
        FvsDevice fvsDevice = fvsDeviceMapper.selectByPrimaryKey(deviceId);
        if (fvsDevice == null) {
            return;
        }
        String deviceName = fvsDevice.getName();
        String deviceSerial = fvsDevice.getUsername();
        //萤石云API 获取直播通道列表
        List<EzvizChannelInfo> channelList = EzvizApi.getChannelList(accessToken, deviceSerial);
        if (channelList.isEmpty()) {
            return;
        }
        for (EzvizChannelInfo channelInfo : channelList) {
            //获取通道号
            Integer channelNo = channelInfo.getChannelNo();
            //多通道设备创建
            if (FvsDeviceType.DVR.getValue().equals(fvsDevice.getDeviceType())) {
                //创建设备
                FvsDevice device = new FvsDevice();
                BeanUtils.copyProperties(fvsDevice, device);
                device.setId(null);
                device.setPid(fvsDevice.getId());
                device.setDeviceType(FvsDeviceType.IPC.getValue());
                device.setChannelNo(channelNo);
                device.setDeviceStatus(channelInfo.getStatus() == 1 ? 1 : 0);
                device.setName(deviceName + ":" + channelNo);
                device.setPtz(FvsDevicePtzStatus.SUPPORT_PTZ.getValue());
                fvsDeviceMapper.insertSelective(device);
            } else {
                fvsDevice.setChannelNo(channelNo);
            }
            fvsDevice.setDeviceStatus(channelInfo.getStatus() == 1 ? 1 : 0);

        }
        fvsDeviceMapper.updateByPrimaryKeySelective(fvsDevice);
    }

    /**
     * 是否支持云台
     *
     * @param accessToken  accessToken
     * @param deviceSerial 设备序列号
     * @return 是否支持云台
     */
    private FvsDevicePtzStatus isSupportPtz(String accessToken, String deviceSerial) {
        FvsDevicePtzStatus status = FvsDevicePtzStatus.NOT_SUPPORT_PTZ;
        EzvizDevicePtzStatus supportPtz = EzvizApi.isSupportPtz(accessToken, deviceSerial);
        if (supportPtz != null) {
            status = FvsDevicePtzStatus.parseValue(supportPtz.getValue());
        }
        return status;
    }


    /**
     * 初始化token
     *
     * @param appKey    appKey
     * @param appSecret appSecret
     * @return token
     */
    public String initAccessToken(String appKey, String appSecret) {
        //萤石云API 获取登录token
        return EzvizApi.getAccessToken(appKey, appSecret);
    }


}
